﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using DevEnverModal;
using QuailDashboard.View.Data;
using QuailDashboard.View.Helpers;
using QuailDashboard.View.Models;
using QuailDashboard.View.QuailServiceReference;

namespace QuailDashboard.View.Controls
{
    public partial class ConfigureEnvironmentControl
    {
        private readonly PageState _pageState = new PageState();
        private readonly Dictionary<string, bool> _hashNames = new Dictionary<string, bool>();

        public ConfigureEnvironmentControl()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Gets or sets the ModalControl manager for this instance
        /// </summary>
        public ModalControl Modal
        {
            get;
            set;
        }

        public TestEnvironment Environment
        {
            get
            {
                return _pageState.Environment;
            }

            set
            {
                _pageState.Environment = value;
            }
        }

        public event EventHandler Finished;

        private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
        {
            LayoutRoot.DataContext = _pageState;
            var service = QuailDataServiceFactory.CreateClient();
            service.GetEnvironmentSettingsCompleted += OnGetEnvironmentSettingsCompleted;
            service.GetEnvironmentSettingsAsync(Environment.TestEnvironmentId);
            _pageState.IncProcessing("Loading...");
        }

        private void OnGetEnvironmentSettingsCompleted(object sender, GetEnvironmentSettingsCompletedEventArgs e)
        {
            _pageState.DecProcessing();

            if (e.Error != null)
            {
                App.CurrentApp.ShowError("Error getting environment settings", e.Error);
            }
            else
            {
                var collection = new ObservableCollection<EnvironmentSettingData>();
                _hashNames.Clear();
                
                foreach (var result in e.Result)
                {
                    var esd = new EnvironmentSettingData(result.SettingName, result.SettingValue);

                    var hasDupe = _hashNames.Any(n => n.Key == result.SettingName);
                    if (hasDupe)
                    {
                        var dupe = collection.Single(c => c.Name == result.SettingName);
                        if (String.IsNullOrEmpty(dupe.Value) && !String.IsNullOrEmpty(result.SettingValue))
                        {
                            collection.Remove(dupe);
                            _hashNames.Remove(result.SettingName.ToLower().Trim());
                        }
                        else
                        {
                            continue;
                        }                        
                    }
                     
                    collection.Add(esd);

                    _hashNames.Add(result.SettingName.ToLower().Trim(), true);
                }

                GridValues.ItemsSource = collection;
            }
        }

        private void ButtonCancel_Click(object sender, RoutedEventArgs e)
        {
            FireFinished();
        }

        private void ButtonSave_Click(object sender, RoutedEventArgs e)
        {
            // save changes here
            var col = GridValues.ItemsSource as ObservableCollection<EnvironmentSettingData>;
            if (col == null)
                return;

            _pageState.IncProcessing("Saving...");
            // .Where(c => _hashNames.Any(h => h.Value && h.Key == c.Name.ToLower().Trim()))
            var saving = new SavingDataClass(col, Environment.TestEnvironmentId, _hashNames);
            saving.OnCompleteSave += SavingComplete;
            saving.Go();
        }

        private void SavingComplete(object sender, EventArgs e)
        {
            var saving = (SavingDataClass) sender;

            if (!saving.HadErrors)
                FireFinished();
        }

        private class SavingDataClass
        {
            private readonly List<EnvironmentSettingData> _data;
            private readonly int _testEnvironmentId;
            private readonly Dictionary<string, bool> _hashNames;
            private bool _isfirst = true;
            private bool _complete;

            public SavingDataClass(IEnumerable<EnvironmentSettingData> datalist, int testenvironmentid, Dictionary<string, bool> hash)
            {
                _data = datalist.ToList();
                _testEnvironmentId = testenvironmentid;
                _hashNames = hash;
                Service = QuailDataServiceFactory.CreateClient();
                Service.DeleteEnvironmentSettingCompleted += OnDeleteComplete;
                Service.SetEnvironmentSettingValueCompleted += OnSetComplete;
            }

            public event EventHandler OnCompleteSave;
            public bool HadErrors
            {
                get; private set;
            }

            private QuailDataServiceClient Service
            {
                get; set;
            }

            public void Go()
            {
                if (_isfirst)
                {
                    _isfirst = false;

                    for (var i = 0; !_complete && i < 3; i++)
                        Go();
                    return;
                }

                var data = NextData();

                if (data != null)
                {
                    if (data.Name.Trim().Length > 0)
                        Service.SetEnvironmentSettingValueAsync(_testEnvironmentId, data.Name, data.Value);
                    else
                        Go();
                    return;
                }

                var remove = NextRemove();
                if (remove != null)
                {
                    Service.DeleteEnvironmentSettingAsync(_testEnvironmentId, remove);
                    return;
                }

                FireComplete();
            }

            private void OnDeleteComplete(object sender, AsyncCompletedEventArgs e)
            {
                if (e.Error != null)
                {
                    App.CurrentApp.ShowError("Error removing setting!", e.Error);
                    HadErrors = true;
                    FireComplete();
                }
                else
                    Go();
            }

            private void OnSetComplete(object sender, AsyncCompletedEventArgs e)
            {
                if (e.Error != null)
                {
                    App.CurrentApp.ShowError("Error saving setting!", e.Error);
                    HadErrors = true;
                    FireComplete();
                }
                else
                    Go();
            }

            private void FireComplete()
            {
                _complete = true;
                if (OnCompleteSave != null)
                    OnCompleteSave(this, EventArgs.Empty);
            }

            private string NextRemove()
            {
                if (_hashNames.Count == 0)
                    return null;

                var result = _hashNames.Keys.First();
                _hashNames.Remove(result);
                return result;
            }

            private EnvironmentSettingData NextData()
            {
                if (_data.Count == 0)
                    return null;

                var result = _data[0];
                _data.RemoveAt(0);

                _hashNames.Remove(result.Name.ToLower().Trim());

                return result;
            }


        }


        private void FireFinished()
        {
            Modal.HideModal();
            if (Finished != null)
                Finished(this, EventArgs.Empty);
        }

        public class PageState : IsProcessingStateModel
        {
            private TestEnvironment _environment;
            private string _environmentName, _environmentDesc;

            public string Caption
            {
                get
                {
                    if (Environment != null)
                        return "Edit Settings for " + Environment.EnvironmentName;
                    return "Edit Settings";
                }
            }

            public TestEnvironment Environment
            {
                get
                {
                    return _environment;
                }

                set
                {
                    _environment = value;
                    NotifyPropertyChanged("Environment");
                    NotifyPropertyChanged("Caption");
                }
            }

            public string EnvironmentName
            {
                get
                {
                    if (_environment != null && _environmentName == null)
                        _environmentName = _environment.EnvironmentName;

                    return _environmentName;
                }

                set
                {
                    _environmentName = value;
                    NotifyPropertyChanged("EnvironmentName");
                }
            }

            public string EnvironmentDescription
            {
                get
                {
                    if (_environment != null && _environmentDesc == null)
                        _environmentDesc = _environment.Description;

                    return _environmentDesc;
                }

                set
                {
                    _environmentDesc = value;
                    NotifyPropertyChanged("EnvironmentDescription");
                }
            }
        }
    }
}
